using System;
using System.Net;
using System.Net.Sockets;

namespace SpoonCore
{
	public class SpoonSocket
	{
		public event MessageHandler.OnDataReceiveHandler OnDataReceive;

		private readonly Socket _socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

		private bool _running = true;

		public SpoonSocket()
			: this(0)
		{
		}

		public SpoonSocket(int port)
		{
			_socket.Bind(new IPEndPoint(IPAddress.Any, port));
			SocketState ss = new SocketState(_socket);
			ss.Socket.BeginReceiveMessageFrom(ss.Buffer, 0, ss.Buffer.Length, SocketFlags.None, ref ss.EndPoint, ReceiveMessage, ss);
		}

		private void ReceiveMessage(IAsyncResult ar)
		{
			if (_running)
			{
				SocketState ss = (SocketState)ar.AsyncState;

				int count = ss.Socket.EndReceiveMessageFrom(ar, ref ss.Flags, ref ss.EndPoint, out ss.PacketInformation);
				byte[] tmp = new byte[count];
				Array.Copy(ss.Buffer, tmp, count);

				if (OnDataReceive != null) OnDataReceive(tmp, (IPEndPoint)ss.EndPoint);

				ss.Socket.BeginReceiveMessageFrom(ss.Buffer, 0, ss.Buffer.Length, SocketFlags.None, ref ss.EndPoint, ReceiveMessage, ss);
			}
		}

		public void SendMessage(IPEndPoint dest, byte[] data)
		{
			_socket.SendTo(data, dest);
		}

		private class SocketState
		{
			public SocketState(Socket socket)
			{
				Socket = socket;
			}

			public readonly byte[] Buffer = new byte[65536];
			public readonly Socket Socket;
			public EndPoint EndPoint = new IPEndPoint(IPAddress.Any, 0);
			public SocketFlags Flags = SocketFlags.None;
			public IPPacketInformation PacketInformation;
		}

		public void Send(IPEndPoint endPoint, byte[] data)
		{
			if (_running) _socket.SendTo(data, endPoint);
			else { }
		}

		public void Dispose()
		{
			_running = false;
		}
	}
}